/**
 * @version 1.0
 * @author Ha Giang
 * @date
 */
package Communications;

import Configuration.Utils;
import java.io.*;
import java.net.*;
import java.util.*;
import java.util.concurrent.*;

/**
 * This class extends a Thread. Every time there is a message in the channel it's handling,
 * it put the message in a queue. The caller just needs to take care of that queue.
 * 
 */
class MulticastByChannel extends Thread {

    private MulticastSocket msocket;
    private InetAddress group;
    int channel;//port number
    private DatagramPacket recv;
    //announcement: the list of messages sent in this channel
    private Queue<String> annoucenment = new ConcurrentLinkedQueue();

    /**
     * Constructor
     * @param mul_ip_group Multi-cast address
     * @param channel The channel/port number
     */
    public MulticastByChannel(String mul_ip_group, int channel) {
        System.out.print("...Joining Multicast Group: " + mul_ip_group + " Port:"
                + Utils.chnnl2Str(channel) + "...");
        try {
            this.group = InetAddress.getByName(mul_ip_group);
            this.channel = channel;
            msocket = new MulticastSocket(channel);
            msocket.setReuseAddress(false);
            msocket.setLoopbackMode(false);
            msocket.setTimeToLive(3);
            msocket.joinGroup(group);
            start();  //call run
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            System.out.println("Done!");
        }
    }

    @Override
    public void run() {
        byte[] buf = new byte[1000];
        String tmp;
        try {
            for (;;) {
                // Handle the incoming data and print it to stnd output.
                recv = new DatagramPacket(buf, buf.length);
                msocket.receive(recv);
                tmp = //recv.getAddress().getHostAddress() + "|"+ 
                        new String(recv.getData(), 0, recv.getLength());
                //tmp += " From " + recv.getAddress().toString() + " port: " + recv.getPort();
                System.out.println("Received: \"" + tmp + "\" on channel "
                        + Utils.chnnl2Str(channel));
                annoucenment.add(tmp);
            }
        } catch (IOException e) {
            System.out.println("Exit...");
            e.printStackTrace();
        } finally {
            msocket.close();
        }
    }

    /**
     * Announce a message in this channel
     *
     * @param msg The message to send
     */
    public void announceMsg(String msg) {
        System.out.print("Broadcasting \"" + msg + "\" on channel "
                + Utils.chnnl2Str(channel) + "...");
        try {
            if (msocket != null) {
                DatagramPacket dp = new DatagramPacket(msg.getBytes(), msg.length(), group, channel);
                msocket.send(dp);
            } else {
                System.out.println("Socket is null");
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            System.out.println("...Sent!");
        }
    }

    /**
     * Close this channel
     */
    public void closeChannel() {
        msocket.close();
        interrupt();
    }

    /**
     * Get the list of messages (announcement) sent in this channel
     *
     * @return A queue stores messages
     */
    public Queue getAnnouncement() {
        return annoucenment;
    }
}